package com.bckj.fastboot.flow.process;

import com.bckj.fastboot.core.lang.exception.BusinessException;
import com.bckj.fastboot.core.operation.context.OperationContext;
import com.bckj.fastboot.core.util.ExecutionContext;
import com.bckj.fastboot.core.util.SpringUtils;
import com.bckj.fastboot.flow.model.BpmnProcess;
import com.bckj.fastboot.flow.process.consumer.BpmnProcessConsumer;
import com.bckj.fastboot.flow.process.consumer.CustomBpmnProcessConsumer;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.util.concurrent.Executor;

@Slf4j
@RequiredArgsConstructor
public class BpmnProcessExecutor {

    private final BpmnProcessProvider bpmnProcessProvider;
    @Resource(name = "flowThreadPool")
    private Executor executor;

    /**
     * 执行流程 by Execution Service
     */
    public void execute(String processId, ExecutionContext context) {
        execute(processId, context, SpringUtils.getBean(CustomBpmnProcessConsumer.class));
    }

    /**
     * 执行流程 by Process Consumer
     */
    public void execute(String processId, ExecutionContext context, BpmnProcessConsumer bpmnProcessConsumer) {
        BpmnProcess bpmnProcess = bpmnProcessProvider.getProcess(processId);
        Assert.notNull(bpmnProcess, "流程不存在，processId=" + processId);
        BpmnExecVisitor visitor = new BpmnExecVisitor(executor, bpmnProcess, context, bpmnProcessConsumer);
        Throwable error = null;
        try {
            bpmnProcess.execute(visitor);
        } catch (Exception e) {
            error = e;
        }
        if (context instanceof OperationContext oc) {
            if (error != null) {
                if (oc.asyncRollback()) {
                    Throwable finalError = error;
                    executor.execute(() -> bpmnProcessConsumer.rollback(context, finalError));
                } else {
                    bpmnProcessConsumer.rollback(context, error);
                }
                throw new BusinessException(error.getMessage());
            } else {
                if (oc.asyncCallback()) {
                    executor.execute(() -> bpmnProcessConsumer.callback(context));
                } else {
                    bpmnProcessConsumer.callback(context);
                }
            }
        } else {
            if (error != null) {
                bpmnProcessConsumer.rollback(context, error);
            } else {
                bpmnProcessConsumer.callback(context);
            }
        }
    }
}
